// 用于保存要收集的effect函数
let activeEffect = null;
/* 
注册指定的effect函数的函数
功能名称应该叫registerEffect, 但源码中叫effect
fn: 传入的才是effect函数
*/
export function effect(fn) {
  // 将传入的函数保存为当前efffect函数
  activeEffect = fn;
  // 调用effect函数, 函数内部会读取响应式数据, 触发收集当前effect函数
  activeEffect();
  // 重置当前effect函数
  activeEffect = null;
}

/* 
用来保存被代理对象的所有依赖effect集合的map容器
  key: 是一个目标对象, value是map对象
目标对象对应的map对象
  key: 属性名, value是set对象
set对象
  依赖此属性的所有effect函数
*/
const targetMap = new WeakMap();

/* 
追踪/收集 依赖的effect
*/
function track(target, key) {
  // 如果当前没有effect函数, 直接结束
  if (!activeEffect) return;

  // 获取目标对象对应的map对象, 如果没创建一个并保存起来
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  // 根据属性名获取对应的set对象, 如果没有创建一个并保存起来
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  // 将当前的effect保存到set对象中
  dep.add(activeEffect);
}

/* 
触发依赖
也就调用指定目标对象中指定key对应的所有effect函数
*/
function trigger(target, key) {
  let depsMap = targetMap.get(target);
  if (depsMap) {
    const dep = depsMap.get(key);
    if (dep) {
      dep.forEach(effect => effect());
    }
  }
}



// 判断是否为对象 ，注意排除 null
const isObject = val => val !== null && typeof val === 'object';

/* 
reactive函数
*/
export function reactive(target) {
  // 如果target不是对象, 直接返回它, 不做各应式处理
  if (!isObject(target)) return target;

  const handler = {
    get(target, key, receiver) {
      console.log(`获取对象属性${key}值`);
      // 追踪收集依赖
      track(target, key)
      // 利用Reflect得到对应的属性值
      const result = Reflect.get(target, key, receiver);
      // 如果属性值也是对象, 创建并返回对应的代理对象, 否则返回原结果值
      return isObject(result) ? reactive(result) : result;
    },

    set(target, key, value, receiver) {
      console.log(`设置对象属性${key}值`);

      // 获取旧的属性值
      const oldValue = Reflect.get(target, key, reactive);

      let result = true;
      // 如果新值不等于旧值
      if (oldValue !== value) {
        // 通过Reflect设置属性
        result = Reflect.set(target, key, value, receiver);
        // 如果操作成功, 触发依赖effect执行
        if (result) {
          trigger(target, key)
        }
      }
      return result;
    },

    deleteProperty(target, key) {
      console.log(`删除对象属性${key}值`);

      // 如果存在此属性, 通过Reflect删除属性
      const result = target.hasOwnProperty(key) && Reflect.deleteProperty(target, key);
      // 如果操作成功, 触发依赖effect执行
      if (result) {
        trigger(target, key)
      }

      return result;
    },
  };
  return new Proxy(target, handler);
}

// 转换value: 如果val是对象, 生成对应的proxy对象返回 
const convert = val => isObject(val) ? reactive(val) : val;

// 用于创建ref对象的类
class RefImpl {
  constructor(value) {
    // 保存传入的值
    this._rawValue = value;
    // 保存当前是ref对象的标识
    this.__v_isRef = true;
    // 对value进行转换后保存
    this._value = convert(value);
  }
  // value属性的getter: 追踪收集依赖, 返回转换后的value
  get value() {
    console.log('ref getter')
    // 追踪依赖
    track(this, 'value');
    // 返回保存的转换后的value
    return this._value;
  }
  
  // value属性的setter: 对新的value进行转换后保存, 触发依赖effect执行
  set value(newValue) {
    console.log('ref setter')
    // 如果value有变化
    if (newValue !== this._rawValue) {
      // 保存传入的value
      this._rawValue = newValue;
      // 对value转换后保存
      this._value = convert(newValue);
      // 触发依赖effect执行
      trigger(this, 'value');
    }
  }
}

/* 
ref函数
*/
export function ref(value) {
  // 如果value是ref对象, 直接返回它
  if (isObject(value) && value.__v_isRef) return value;
  // 创建对应的ref对象, 并返回
  return new RefImpl(value);
}